package com.study.config;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.study.constant.CacheConstant;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;

import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedHashMap;

/**
 * @author canace
 * @version 1.0
 * @description cache二级缓存配置类
 * @date 2024/1/27 11:04
 */

@Configuration
public class CacheConfig {

    /**
     * caffeine缓存管理器
     *
     * @return 缓存管理器
     */
    @Bean
    @Primary
    public CacheManager caffeineCacheManager() {
        SimpleCacheManager simpleCacheManager = new SimpleCacheManager();

        ArrayList<CaffeineCache> caches = new ArrayList<>(CacheConstant.CacheEnum.values().length);

        // 遍历所有的缓存枚举，创建对应的缓存对象
        for (var c : CacheConstant.CacheEnum.values()) {
            // 只有本地缓存才会创建
            if (c.isLocal()) {
                // 创建缓存对象
                Caffeine<Object, Object> caffeine = Caffeine.newBuilder().recordStats().maximumSize(c.getMaxSize());
                // 如果设置了过期时间，就设置过期时间
                if (c.getTtl() > 0) {
                    caffeine.expireAfterWrite(Duration.ofSeconds(c.getTtl()));
                }
                // 将缓存对象添加到缓存管理器中
                caches.add(new CaffeineCache(c.getName(), caffeine.build()));
            }
        }
        // 将所有的缓存对象添加到缓存管理器中
        simpleCacheManager.setCaches(caches);
        return simpleCacheManager;
    }

    /**
     * redis缓存管理器
     *
     * @param redisConnectionFactory redis连接工厂
     * @return 缓存管理器
     */
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 创建redis缓存管理器
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        // 设置redis缓存配置
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .disableCachingNullValues()
                .prefixCacheNameWith(CacheConstant.REDIS_CACHE_PREFIX)
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        LinkedHashMap<String, RedisCacheConfiguration> cacheMap = new LinkedHashMap<>(CacheConstant.CacheEnum.values().length);

        // 遍历所有的缓存枚举，创建对应的缓存对象
        for (var c : CacheConstant.CacheEnum.values()) {
            // 只有远程缓存才会创建
            if (c.isRemote()) {
                // 如果设置了过期时间，就设置过期时间
                if (c.getTtl() > 0) {
                    cacheMap.put(c.getName(), RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
                            .prefixCacheNameWith(CacheConstant.REDIS_CACHE_PREFIX)
                            .entryTtl(Duration.ofSeconds(c.getTtl()))
                            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())));
                } else {
                    cacheMap.put(c.getName(), RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
                            .prefixCacheNameWith(CacheConstant.REDIS_CACHE_PREFIX)
                            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())));
                }
            }
        }
        // 创建redis缓存管理器
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter, redisCacheConfiguration, cacheMap);
        // 设置事务支持
        redisCacheManager.setTransactionAware(true);
        // 初始化缓存
        redisCacheManager.initializeCaches();
        return redisCacheManager;
    }
}
